package com.wsoft.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wsoft.query.job.*;
import com.wsoft.utils.job.JobClientManager;
import com.wsoft.core.exception.Asserts;
import com.wsoft.entity.TsJobEntity;
import com.wsoft.enums.JobStatusEnum;
import com.wsoft.manager.TsJobManager;
import com.wsoft.mapper.TsJobMapper;
import com.wsoft.service.ITsJobService;
import com.wsoft.utils.JobUtil;
import com.wsoft.vo.JobVO;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 定时任务表 服务实现类
 * </p>
 *
 * @author z001
 * @since 2024年10月23日 08:16:34
 */
@Service
public class TsJobServiceImpl extends ServiceImpl<TsJobMapper, TsJobEntity> implements ITsJobService {

    @Resource
    private TsJobManager jobManager;
    @Resource
    private JobClientManager jobClientManager;

    /**
     * 默认返回执行次数
     */
    private final Integer cornCount = 5;
    /**
     * 新增任务
     *
     * @param query
     * @return
     */
    @Override
    public boolean insertJob(JobInsertQuery query) {
        //校验code
        validateJobCode(query);
        //校验corn
        validateCorn(query.getCron());
        //保存
        TsJobEntity entity = Convert.convert(TsJobEntity.class, query);
        entity.setStatus(JobStatusEnum.PAUSE.getType());
        return jobManager.save(entity);
    }

    /**
     * 修改任务
     *
     * @param query
     * @return
     */
    @Override
    public boolean updateJob(JobUpdateQuery query) {
        TsJobEntity jobEntity = jobManager.getById(query.getId());
        //校验任务状态
        validateJobStatus(jobEntity.getStatus());
        //校验code
        validateJobCode(query);
        //校验corn
        validateCorn(query.getCron());

        TsJobEntity entity = Convert.convert(TsJobEntity.class, query);
        entity.setStatus(JobStatusEnum.PAUSE.getType());
        return jobManager.updateById(entity);
    }

    /**
     * 查询任务列表
     *
     * @param query
     * @return
     */
    @Override
    public PageInfo<JobVO> listJob(JobListQuery query) {
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        List<TsJobEntity> entityList = jobManager.listJob(query);
        List<JobVO> result = new ArrayList<>();
        for (TsJobEntity entity : entityList) {
            JobVO vo  = Convert.convert(JobVO.class, entity);
            if(JobStatusEnum.START.getType().equals(vo.getStatus())){
                //赋值后几次运行时间
                List<LocalDateTime> nextTimeList = JobUtil.queryNextTimeFromNow(entity.getCron(), cornCount);
                vo.setNextJobExecuteTimeList(nextTimeList);
            }
            result.add(vo);
        }
        return PageInfo.of(result);
    }

    /**
     * 获取任务详情
     * @param id
     * @return
     */
    @Override
    public JobVO getJobInfo(Long id) {
        TsJobEntity entity = jobManager.getById(id);
        if(null == entity){
            return new JobVO();
        }
        JobVO vo  = Convert.convert(JobVO.class, entity);
        // 计算未来5次执行时间
        if (JobStatusEnum.START.getType().equals(entity.getStatus())) {
            List<LocalDateTime> nextTimeList = JobUtil.queryNextTimeFromNow(entity.getCron(), cornCount);
            vo.setNextJobExecuteTimeList(nextTimeList);
        }
        return vo;
    }

    /**
     * 删除任务
     * @param id
     * @return
     */
    @Override
    public boolean deleteJob(Long id) {
        TsJobEntity jobEntity = jobManager.getById(id);
        //校验任务状态
        validateJobStatus(jobEntity.getStatus());
        boolean b = jobManager.removeById(id);
        if(b){
            jobClientManager.removeJob(jobEntity);
        }
        return b;
    }

    /**
     * 修改job状态
     *
     * @param query
     * @return
     */
    @Override
    public boolean updateStatus(JobUpdateQuery query) {
        TsJobEntity jobEntity = jobManager.getById(query.getId());
        if(jobEntity.getStatus().equals(query.getStatus())){
            return true;
        }
        jobEntity.setStatus(query.getStatus());
        boolean b = jobManager.updateById(jobEntity);
        if(b){
            jobClientManager.updateJob(jobEntity);
        }
        return b;
    }

    /**
     * 执行一次
     * @param query
     */
    @Override
    public boolean executeJobOne(JobExecutorQuery query) {
        TsJobEntity jobEntity = jobManager.getById(query.getId());
        if(StrUtil.isNotBlank(query.getParams())){
            jobEntity.setParams(query.getParams());
        }
        return jobClientManager.executeJob(jobEntity);
    }

    @Override
    public List<LocalDateTime> nextExecute(JobNextExecutorQuery query) {
        //验证表达式
        validateCorn(query.getCron());
        if(query.getCount() == 0){
            query.setCount(cornCount);
        }
        return JobUtil.queryNextTimeFromNow(query.getCron(), query.getCount());
    }


    //############################### 私有函数 ###############################


    /**
     * 校验 Code 是否存在
     */
    private <T extends JobBaseQuery> void validateJobCode(T query) {
        TsJobEntity entity = jobManager.getByCode(query.getCode());
        if (query instanceof JobInsertQuery && null != entity) {
            //页面编码已存在
            Asserts.fail("[ts.code.exist]");
        }
        if (query instanceof JobUpdateQuery &&
                null != entity &&
                !((JobUpdateQuery) query).getId().equals(entity.getId())) {
            //页面编码已存在
            Asserts.fail("[ts.code.exist]");
        }
    }

    /**
     * 校验 任务 状态
     *
     * @param status
     */
    private void validateJobStatus(Integer status) {
        if (JobStatusEnum.START.getType().equals(status)) {
            //暂停状态下才能操作
            Asserts.fail("[job.pause.continue]");
        }
    }

    /**
     * 验证cron表达式
     * @param cron
     */
    private void validateCorn(String cron){
        if(StrUtil.isBlank(cron) || !CronExpression.isValidExpression(cron)){
            //corn 格式不正常
            Asserts.fail("[job.cron.error]");
        }
    }
}
